/*-------------------------------------------------------------------------
 *
 * palloc.h
 *	  POSTGRES 内存分配器的定义。
 *
 * 本文件包含几乎所有后端模块所需的基本内存分配接口。
 * 它直接由 postgres.h 包含，因此这里的定义在所有地方都自动可用。
 * 保持精简！
 *
 * 内存分配发生在“上下文”中。通过 palloc()/MemoryContextAlloc() 
 * 获得的每个块都在特定的上下文中分配。
 * 上下文的整个内容可以通过重置或删除该上下文来轻松快速地释放——
 * 这种方式比单独释放块更快，并且更不容易出现内存泄漏错误。
 * 我们将上下文组织成上下文树，以便在保留释放所有应释放内容的
 * 确定性的同时，实现对块生命周期的精细控制。有关更多信息，
 * 请参见 utils/mmgr/README。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/palloc.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PALLOC_H
#define PALLOC_H

/*
 * Type MemoryContextData 在 nodes/memnodes.h 中声明。
 * 大多数内存分配的用户应该将其视为一种抽象类型，因此我们
 * 不在此处提供结构内容。
 */
typedef struct MemoryContextData *MemoryContext;

/*
 * 一个内存上下文可以注册回调函数。任何这样的
 * 函数将在上下文下一个重置或删除之前被调用一次。
 * 描述此类回调的 MemoryContextCallback 结构通常会在上下文本身内分配，
 * 从而避免显式管理的需要（重置/删除操作将释放它）。
 */
typedef void (*MemoryContextCallbackFunction) (void *arg);

typedef struct MemoryContextCallback
{
	MemoryContextCallbackFunction func; /* 要调用的函数 */
	void	   *arg;			/* 传递给它的参数 */
	struct MemoryContextCallback *next; /* 回调列表中的下一个 */
} MemoryContextCallback;

/*
 * CurrentMemoryContext 是 palloc() 的默认分配上下文。
 * 避免直接访问！相反，请使用 MemoryContextSwitchTo()
 * 来更改设置。
 */
extern PGDLLIMPORT MemoryContext CurrentMemoryContext;

/*
 * MemoryContextAllocExtended 的标志。
 */
#define MCXT_ALLOC_HUGE			0x01	/* 允许大分配（> 1 GB） */
#define MCXT_ALLOC_NO_OOM		0x02	/* 如果内存不足则不失败 */
#define MCXT_ALLOC_ZERO			0x04	/* 零分配内存 */

/*
 * 基本内存分配操作（更多在 utils/memutils.h 中）
 */
extern void *MemoryContextAlloc(MemoryContext context, Size size);
extern void *MemoryContextAllocZero(MemoryContext context, Size size);
extern void *MemoryContextAllocZeroAligned(MemoryContext context, Size size);
extern void *MemoryContextAllocExtended(MemoryContext context,
										Size size, int flags);

extern void *palloc(Size size);
extern void *palloc0(Size size);
extern void *palloc_extended(Size size, int flags);
extern pg_nodiscard void *repalloc(void *pointer, Size size);
extern void pfree(void *pointer);

/*
 * 更易于书写且类型安全性更高的变体
 */

/*
 * 为类型为“type”的一个对象分配空间
 */
#define palloc_object(type) ((type *) palloc(sizeof(type)))
#define palloc0_object(type) ((type *) palloc0(sizeof(type)))

/*
 * 为类型为“type”的“count”个对象分配空间
 */
#define palloc_array(type, count) ((type *) palloc(sizeof(type) * (count)))
#define palloc0_array(type, count) ((type *) palloc0(sizeof(type) * (count)))


/*
 * 将“pointer”所指向的分配大小更改为具有“count”个
 * 类型为“type”的对象的空间
 */
#define repalloc_array(pointer, type, count) ((type *) repalloc(pointer, sizeof(type) * (count)))

/*
 * palloc() 的结果总是按照字对齐，因此在决定使用哪个 MemSet 变体时，
 * 我们可以跳过对指针对齐的测试。注意，此变体没有提供任何优势，
 * 不应使用，除非其 "sz" 参数是编译时常量；因此，多个
 * 次评估参数的问题在实际中并不是问题。
 */
#define palloc0fast(sz) \
	( MemSetTest(0, sz) ? \
		MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) : \
		MemoryContextAllocZero(CurrentMemoryContext, sz) )

/* 较高限制的分配器。 */
extern void *MemoryContextAllocHuge(MemoryContext context, Size size);
extern pg_nodiscard void *repalloc_huge(void *pointer, Size size);

/*
 * 尽管此头文件名义上仅限后端，但某些前端
 * 程序如 pg_controldata 通过 postgres.h 引入它。
 * 对于某些编译器，在这种情况下需要隐藏 MemoryContextSwitchTo 的内联定义；
 * 因此 #ifndef FRONTEND。
 */

#ifndef FRONTEND
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
	MemoryContext old = CurrentMemoryContext;

	CurrentMemoryContext = context;
	return old;
}
#endif							/* FRONTEND */

/* 注册内存上下文重置/删除回调 */
extern void MemoryContextRegisterResetCallback(MemoryContext context,
											   MemoryContextCallback *cb);

/*
 * 这些类似于标准的 strdup()，除了复制的字符串是在上下文中分配的，而不是使用 malloc()。
 */
extern char *MemoryContextStrdup(MemoryContext context, const char *string);
extern char *pstrdup(const char *in);
extern char *pnstrdup(const char *in, Size len);

extern char *pchomp(const char *in);

/* sprintf 到 palloc 的缓冲区 --- 这些在 psprintf.c 中 */
extern char *psprintf(const char *fmt,...) pg_attribute_printf(1, 2);
extern size_t pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) pg_attribute_printf(3, 0);

#endif							/* PALLOC_H */
